package aryn.framework.graphic;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;

public class Transform {
//	v1.2
	
	/*	Sommario:
	 * 
	 * 	flipH				: riflette l'immagine orizzontalmente
	 * 	flipV				: riflette l'immagine verticalmente
	 * 	resizeTo			: ridimensiona l'immagine alle nuove dimensioni
	 * 	stretch				: ridimensiona l'immagine in percentuale, mantenendo le proporzioni
	 * 	stretch				: ridimensiona in percentuale orizzontalmente e verticalmente
	 * 	crop				: ritaglia l'immagine secondo il rettangolo fornito
	 * 	cropToMinSize		: ritaglia tutte le immagini dell'array, eliminando i bordi trasparenti in eccesso
	 * 	rotate90CCW			: ruota l'immagine di 90 gradi in senso antiorario
	 * 	rotate90CW			: ruota l'immagine di 90 gradi in senso orario
	 */
	
	// ------------------------------------------------------------------------- \\
	
	private Transform() {}

	
	/* riflette l'immagine orizzontalmente
	 * 
	 * input : immagine di partenza
	 * output: immagine riflessa
	 */
	public static BufferedImage flipH(BufferedImage img) {   
		int w = img.getWidth();   
		int h = img.getHeight();   
		BufferedImage dimg = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);   
		Graphics2D g = dimg.createGraphics();
		g.drawImage(img, w, 0, 0, h, 0, 0, w, h, null);  
		g.dispose();
		return dimg;
	} 
	
	/* riflette l'immagine verticalmente
	 * 
	 * input : immagine di partenza
	 * output: immagine riflessa
	 */
	public static BufferedImage flipV(BufferedImage img) {   
		int w = img.getWidth();   
		int h = img.getHeight();   
		BufferedImage dimg = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
		Graphics2D g = dimg.createGraphics();
		g.drawImage(img, 0, h, w, 0, 0, 0, w, h, null);
		g.dispose();
		return dimg;
	} 
	

	
	/* Ridimensiona l'immagine alle nuove dimensioni
	 * 
	 * input : immagine di partenza, nuove dimensioni
	 * output: immagine ridimensionata
	 */
	public static BufferedImage resizeTo(BufferedImage img, int newW, int newH) {   
		int w = img.getWidth();   
		int h = img.getHeight();   
		BufferedImage dimg = new BufferedImage(newW, newH, BufferedImage.TYPE_INT_ARGB);   
		Graphics2D g = dimg.createGraphics();   
//		g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);   
		g.drawImage(img, 0, 0, newW, newH, 0, 0, w, h, null);   
		g.dispose();   
		return dimg;   
	}
	
	
	/* Ridimensiona l'immagine alle nuove dimensioni
	 * 
	 * input : immagine di partenza, percentuale di ridimensionamento
	 * output: immagine ridimensionata
	 */
	public static BufferedImage stretch(BufferedImage img, int percent) {   
		int w = img.getWidth();   
		int h = img.getHeight();   
		BufferedImage dimg = new BufferedImage((percent*w)/100, (percent*h)/100, BufferedImage.TYPE_INT_ARGB);   
		Graphics2D g = dimg.createGraphics();   
//		g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);   
		g.drawImage(img, 0, 0, (percent*w)/100, + (percent*h)/100, 0, 0, w, h, null);
		g.dispose();   
		return dimg;   
	}
	
	
	/* Ridimensiona la larghezza e l'altenzza alle nuove dimensioni
	 * 
	 * input : immagine di partenza, percentuale di ridimensionamento di larghezza ed altezza
	 * output: immagine ridimensionata
	 */
	public static BufferedImage stretch(BufferedImage img, int percentH, int percentV) {
		int w = img.getWidth();
		int h = img.getHeight();
		BufferedImage dimg = new BufferedImage((percentH*w)/100, (percentV*h)/100, BufferedImage.TYPE_INT_ARGB);
		Graphics2D g = dimg.createGraphics();
//		g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
		g.drawImage(img, 0, 0, (percentH*w)/100, + (percentV*h)/100, 0, 0, w, h, null);
		g.dispose();
		return dimg;
	}
	
	
	/* ritaglia l'immagine secondo il rettangolo fornito
	 * 
	 */
	public static BufferedImage crop(BufferedImage img, int x1, int y1, int x2, int y2) {
		int w = x2 - x1;
		int h = y2 - y1;
		BufferedImage dimg = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
		Graphics2D g = dimg.createGraphics();
		g.drawImage(img, 0, 0, w, h, x1, y1, x2, y2, null);
		g.dispose();
		return dimg;
	}
	
	/* Ritaglia tutte le immagini, eliminando i bordi trasparenti in eccesso
	 * 
	 */
	public static BufferedImage[] cropToMinSize(BufferedImage[] imgs) {
		BufferedImage[] ret = new BufferedImage[imgs.length];
		
		int w = imgs[0].getWidth();
		int h = imgs[0].getHeight();
		Color color = null;
		boolean leftFlag = false, topFlag = false, changeFlag = false;
		int top = 0, bot = 0, left = 0, right = w;
		int bestTop = h, bestBot = 0, bestLeft = w, bestRight = 0;
		int bestTempTop = h, bestTempBot = 0, bestTempLeft = w, bestTempRight = 0;
		
		for(int k = 0; k < imgs.length; k++) {
			BufferedImage img = imgs[k];
			// row first
			for(int j = 0; j < img.getHeight(); j++) {
				for(int i = 0; i < img.getWidth(); i++) {
					color = new Color(img.getRGB(i, j), true);
					if (color.getAlpha() > 0) { //(!(color.getRed() == 0 && color.getGreen() == 0 && color.getBlue() == 0)) {
						leftFlag = true;
						changeFlag = true;
						right = w;
					} else {
						if (leftFlag == false) left++;
						right--;
					}
				}
				if (changeFlag && left < bestTempLeft) bestTempLeft = left;
				if (changeFlag && right > bestTempRight) bestTempRight = right;
				left = 0;			
				right = w;
				leftFlag = false;
				changeFlag = false;
			}
			// column first
			for(int i = 0; i < img.getWidth(); i++) {
				for(int j = 0; j < img.getHeight(); j++) {
					color = new Color(img.getRGB(i, j), true);
					if (color.getAlpha() > 0) { //(!(color.getRed() == 0 && color.getGreen() == 0 && color.getBlue() == 0)) {
						topFlag = true;
						changeFlag = true;
						bot = h;
					} else {
						if (topFlag == false) top++;
						bot--;
					}
				}
				if (changeFlag && top < bestTempTop) bestTempTop = top;
				if (changeFlag && bot > bestTempBot) bestTempBot = bot;
				top = 0;			
				bot = h;
				topFlag = false;
				changeFlag = false;
			}
			if (bestTempLeft < bestLeft) bestLeft = bestTempLeft;
			if (bestTempTop < bestTop) bestTop = bestTempTop;
			if (bestTempRight > bestRight) bestRight = bestTempRight;
			if (bestTempBot > bestBot) bestBot = bestTempBot;
		}
		// now i have the effective dimensions to crop with
		for(int k = 0; k < imgs.length; k++) {
			ret[k] = Transform.crop(imgs[k], bestLeft, bestTop, bestRight, bestBot);
		}
		return ret;
	}
	
	public static BufferedImage cropToMinSize(BufferedImage img) {	
		int w = img.getWidth();
		int h = img.getHeight();
		Color color = null;
		boolean leftFlag = false, topFlag = false, changeFlag = false;
		int top = 0, bot = h, left = 0, right = w;
		int bestTop = h, bestBot = 0, bestLeft = w, bestRight = 0;
		
		// row first
		for(int j = 0; j < img.getHeight(); j++) {
			for(int i = 0; i < img.getWidth(); i++) {
				color = new Color(img.getRGB(i, j), true);
				if (color.getAlpha() > 0) {
					leftFlag = true;
					changeFlag = true;
					right = w;
				} else {
					if (leftFlag == false) left++;
					right--;
				}
			}
			if (changeFlag && left < bestLeft) bestLeft = left;
			if (changeFlag && right > bestRight) bestRight = right;
			left = 0;			
			right = w;
			leftFlag = false;
			changeFlag = false;
		}
		
		// column first
		for(int i = 0; i < img.getWidth(); i++) {
			for(int j = 0; j < img.getHeight(); j++) {
				color = new Color(img.getRGB(i, j), true);
				if (color.getAlpha() > 0) {
					topFlag = true;
					changeFlag = true;
					bot = h;
				} else {
					if (topFlag == false) top++;
					bot--;
				}
			}
			if (changeFlag && top < bestTop) bestTop = top;
			if (changeFlag && bot > bestBot) bestBot = bot;
			top = 0;			
			bot = h;
			topFlag = false;
			changeFlag = false;
		}

		return Transform.crop(img, bestLeft, bestTop, bestRight, bestBot);
	}
	
	
	/*	ruota l'immagine di un angolo arbitrario in senso antiorario
	 * 
	 */
	public static BufferedImage rotateCCW(BufferedImage img, double angleDegree) {
		double angle = Math.toRadians(angleDegree);
		double w = img.getWidth();
		double h = img.getHeight();
		// x' = x * cos(teta) - y * sin(teta)
		// y' = x * sin(teta) + y * cos(teta)
		int o = 9;
		double fi = Math.atan(h/w);
		double diag = Math.sqrt(w*w + h*h);
		int newW = (int) Math.abs(Math.ceil( Math.max(
				Math.abs(diag * Math.cos(angle + fi)) , Math.abs(h * Math.sin(angle) ))));
		int newH = (int) Math.abs(Math.ceil( 
				Math.abs(w * Math.sin(angle)) + Math.abs(h * Math.cos(angle) )));
		
		BufferedImage dimg = new BufferedImage(newW, newH, BufferedImage.TYPE_INT_ARGB); //img.getType());
		Graphics2D g = dimg.createGraphics();
		int drawingX = 0;
		int drawingY = 0;
		
		g.rotate(- angle, w/2, h/2);
		g.drawImage(img, drawingX, drawingY, null);
		g.dispose();
		return dimg;
	}
	
	/*	ruota l'immagine di 90 gradi in senso antiorario
	 * 
	 */
	public static BufferedImage rotate90CCW(BufferedImage img) {   
		int w = img.getWidth();
		int h = img.getHeight();
		BufferedImage dimg = new BufferedImage(h, w, BufferedImage.TYPE_INT_ARGB); //img.getType());
		Graphics2D g = dimg.createGraphics();
		g.rotate(- Math.PI / 2, 0, w);
		g.drawImage(img, 0, w, null);
		g.dispose();
		return dimg;
	}
	
	/*	ruota l'immagine di 90 gradi in senso orario
	 * 
	 */
	public static BufferedImage rotate90CW(BufferedImage img) {   
		int w = img.getWidth();
		int h = img.getHeight();
		BufferedImage dimg = new BufferedImage(h, w, BufferedImage.TYPE_INT_ARGB); //img.getType());
		Graphics2D g = dimg.createGraphics();
		g.rotate(Math.PI / 2, h, 0);
		g.drawImage(img, h, 0, null);
//		g.rotate(Math.PI / 2);
//		g.drawImage(img, 0, -h, null);
		g.dispose();
		return dimg;
	}
}
